# -*- coding:utf-8 -*-

import numpy as np
import newton_raphson as nr
import testing_utils as testUtils
import matplotlib.pyplot as plt

#g(x1,x2,x3) = (x1*x3, x2*x1+6,x3-x1-1, x3*x2-x1)" Diverge
#"h(x,y,z) = (yz-4, xz, xy, xyz)"
def f(X):
	return np.matrix([[np.cos(X[0,0])], [np.sin(X[1,0])]])

def g(X):
	return np.matrix([[X[0,0]*X[2,0]],[X[1,0]*X[0,0]+6],[X[2,0]-X[0,0]-1],[X[2,0]*X[1,0]-X[0,0]]])


def h(X):
	return np.matrix([[X[1,0]*X[2,0]-4],[X[0,0]*X[2,0]],[X[0,0]*X[1,0]],[X[0,0]*X[1,0]*X[2,0]		]])


def Jf(X):
	return np.matrix([[-np.sin(X[0,0]),0],
			  [0, np.cos(X[1,0])]])

def Jg(X):
	return np.matrix(	[[X[2,0],X[1,0],X[2,0],-1],
						 [0,X[0,0],-1,X[2,0]],
						 [X[0,0],0,1,X[1,0]]]).T

def Jh(X):
	return np.matrix([	[0,X[2,0],X[1,0]],
						[X[2,0],0,X[0,0]],
						[X[1,0],X[0,0],0],
						[X[1]*X[2],X[0]*X[2],X[0]*X[1]]])

X = np.array([[1],[1]])
Y = np.array([[-1],[1],[0]])
epsi = 1e-10



print "Testing the validity of the results : "
testUtils.predicate_check(lambda:np.allclose(f(nr.newton_raphson(f,Jf,X, 100, epsi)),np.zeros(X.shape),epsi,epsi),"- f applied to the solution is close to zero")
testUtils.predicate_check(lambda:np.allclose(nr.newton_raphson_simple(f,Jf,X, 100, epsi),nr.newton_raphson_backtrack(f,Jf,X, 100, epsi),epsi,epsi),"- Simple and backtracking method gives similar results")

print "Comparison of methods :"
(res1,time1) = testUtils.execution_time(lambda:nr.newton_raphson_simple(f,Jf,X, 100, epsi),"Simple Newton method")
(res2,time2) = testUtils.execution_time(lambda:nr.newton_raphson_backtrack(f,Jf,X, 100, epsi),"Backtracking Newton method")


currentTest = h
JcurrentTest = Jh
currentVect = Y
testUtils.comparison_function_figure(lambda x:np.linalg.norm(currentTest(nr.newton_raphson_simple(currentTest, JcurrentTest, currentVect, x, epsi))),lambda x:np.linalg.norm(currentTest(nr.newton_raphson_backtrack(currentTest, JcurrentTest, Y, x, epsi))),
									10,"Number of iterations","Norm of the solution's image by h","No backtracking","With backtracking","BacktrackingEffectH")

currentTest = f
JcurrentTest = Jf
currentVect = X
testUtils.comparison_function_figure(lambda x:np.linalg.norm(f(nr.newton_raphson_simple(currentTest, JcurrentTest, currentVect, x, epsi))),lambda x:np.linalg.norm(currentTest(nr.newton_raphson_backtrack(currentTest, JcurrentTest, currentVect, x, epsi))),
									10,"Number of iterations","Norm of the solution's image by f","No backtracking","With backtracking","BacktrackingEffectF")
currentTest = g
JcurrentTest = Jg
currentVect = Y
testUtils.comparison_function_figure(lambda x:np.linalg.norm(currentTest(nr.newton_raphson_simple(currentTest, JcurrentTest, currentVect, x, epsi))),lambda x:np.linalg.norm(currentTest(nr.newton_raphson_backtrack(currentTest, JcurrentTest, Y, x, epsi))),
									100,"Number of iterations","Norm of the solution's image by g","No backtracking","With backtracking","BacktrackingEffectG")
